package com.example.a16;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
import org.springframework.aop.support.StaticMethodMatcherPointcut;
import org.springframework.core.annotation.MergedAnnotations;
import org.springframework.transaction.annotation.Transactional;

import java.lang.reflect.Method;

public class A16Application {

    private static final Logger logger = LoggerFactory.getLogger(A16Application.class);

    public static void main(String[] args) throws NoSuchMethodException {

        logger.debug("pt1 >>>>>>>>>>>>>>");
        AspectJExpressionPointcut pt1 = new AspectJExpressionPointcut();
        pt1.setExpression("execution(* bar())");
        System.out.println(pt1.matches(T1.class.getMethod("foo"), T1.class));
        System.out.println(pt1.matches(T1.class.getMethod("bar"), T1.class));

        logger.debug("pt2 >>>>>>>>>>>>>>");
        AspectJExpressionPointcut pt2 = new AspectJExpressionPointcut();
        pt2.setExpression("@annotation(org.springframework.transaction.annotation.Transactional)");
        System.out.println(pt2.matches(T1.class.getMethod("foo"), T1.class));
        System.out.println(pt2.matches(T1.class.getMethod("bar"), T1.class));

        logger.debug("pt3 >>>>>>>>>>>>>>");
        StaticMethodMatcherPointcut pt3 = new StaticMethodMatcherPointcut() {
            @Override
            public boolean matches(Method method, Class<?> targetClass) {

                // 检查方法上是否加了 @Transactional 注解
                MergedAnnotations annotations = MergedAnnotations.from(method);
                if (annotations.isPresent(Transactional.class)) {
                    return true;
                }

                // 查看类上是否加了 @Transactional 注解
                annotations = MergedAnnotations.from(targetClass, MergedAnnotations.SearchStrategy.TYPE_HIERARCHY);
                if (annotations.isPresent(Transactional.class)){
                    return true;
                }
                return false;
            }
        };

        logger.debug("pt3 >>>>>>>>>>>>>> T1");
        System.out.println(pt3.matches(T1.class.getMethod("foo"), T1.class));
        System.out.println(pt3.matches(T1.class.getMethod("bar"), T1.class));

        logger.debug("pt3 >>>>>>>>>>>>>> T2");
        System.out.println(pt3.matches(T2.class.getMethod("foo"), T2.class));
        logger.debug("pt3 >>>>>>>>>>>>>> T3");
        System.out.println(pt3.matches(T3.class.getMethod("foo"), T3.class));

        /*
            小结:
                1. 底层切点实现是如何匹配的: 调用了 aspectj 的匹配方法
                2. 比较关键的是它实现了 MethodMatcher 接口, 用来执行方法的匹配
         */

    }

    static class T1 {

        @Transactional
        public void foo() {

        }

        public void bar() {

        }
    }

    @Transactional // 该类下的所有方法都要被事务增强
    static class T2 {

        public void foo() {

        }
    }

    @Transactional // 实现类中的方法也会被事务增强
    interface I3 {

        void foo();
    }

    static class T3 implements I3 {

        @Override
        public void foo() {

        }
    }
}
